誠如先前文章所說,Flutter由許多Widgets去組成整個App,從這章節開始會從UI相關的Widgets開始介紹,
順便了解不同Widgets的名稱在Mobile development中的代表的是什麼組件。
在建構一個App,一定會用到的就是Basic widgets,下面會逐一介紹在這個Widget內有哪些類別可以使用。

App bar可由Toobar或是其他Widgets組成,像是TabBar和FlexibleSpaceBar,如圖所見,這是一個常駐於螢幕上方的工具列。
App bar最常見被使用在Scaffold.appBar這個屬性。在這個widget內,預設會提供一個固定高度的app bar在螢幕上方的位置。
AppBar包含許多屬性,有leading、title、actions、bottom和flexibleSpace。
在下圖列出AppBar這個Widget每個插槽的相對位置,排列方式是由左至右。

如圖所示,這是用來將子組件排列成垂直方向的widget,若希望它會自動填滿剩餘空間,需要將其包裝在Expanded 內。
另外,column並沒有有捲動(scroll)效果,如果需要能夠捲動,可以考慮使用ListView。
下方範例示範將widgets垂直排列,並擴展最後一個logo。
Column(
  children: <Widget>[
    Text('Deliver features faster'),
    Text('Craft beautiful UIs'),
    Expanded(
      child: FittedBox(
        fit: BoxFit.contain, // otherwise the logo will be tiny
        child: const FlutterLogo(),
      ),
    ),
  ],
)

這個widget能組合painting、positioning和sizing這些widget,就是常見的容易概念。
首先,放在這個容器內的子組件會先計算出padding,然後套用其被約束(constraints)的寬高,最後
才是計算margin的大小。
以下範例是在Center這個widget內放入一個container,並且描述它的寬高及margin。
Center(
  child: Container(
    margin: const EdgeInsets.all(10.0),
    color: Colors.amber[600],
    width: 48.0,
    height: 48.0,
  ),
)

這個Widget有點奇妙,就是召喚一個Flutter logo出來。可以想到的就是在培訓或是作為demo的產品時可以使用。

在Flutter內,已經內建豐富的icons可供使用。
用法可以參考如下:
Row(
  mainAxisAlignment: MainAxisAlignment.spaceAround,
  children: const <Widget>[
    Icon(
      Icons.favorite,
      color: Colors.pink,
      size: 24.0,
      semanticLabel: 'Text to announce in accessibility modes',
    ),
    Icon(
      Icons.audiotrack,
      color: Colors.green,
      size: 30.0,
    ),
    Icon(
      Icons.beach_access,
      color: Colors.blue,
      size: 36.0,
    ),
  ],
)

用來顯示圖片的Widget,支援格式有:JPEG、PNG、GIF、Animated GIF、WebP、Animated WebP、BMP和WBMP。
圖片可以被多種方式引入:
以下範例是透過其中一種ImageProvider獲得圖片:
const Image(
  image: NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg'),
)

這個Widget會繪製一個Box,用來表示這個地方未實作完成,未來有可能放入別的widget在這個位置上。

這是一個基於Material Design的凸起按鈕。
按鈕本身帶有onPressed這個callback,若這個callback為null,即為disabled的效果。
以下範例分別示範disabled RaisedButton、enabled RaisedButton和漸層(gradient)背景色:
Widget build(BuildContext context) {
  return Center(
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        const RaisedButton(
          onPressed: null,
          child: Text(
            'Disabled Button',
            style: TextStyle(fontSize: 20)
          ),
        ),
        const SizedBox(height: 30),
        RaisedButton(
          onPressed: () {},
          child: const Text(
            'Enabled Button',
            style: TextStyle(fontSize: 20)
          ),
        ),
        const SizedBox(height: 30),
        RaisedButton(
          onPressed: () {},
          textColor: Colors.white,
          padding: const EdgeInsets.all(0.0),
          child: Container(
            decoration: const BoxDecoration(
              gradient: LinearGradient(
                colors: <Color>[
                  Color(0xFF0D47A1),
                  Color(0xFF1976D2),
                  Color(0xFF42A5F5),
                ],
              ),
            ),
            padding: const EdgeInsets.all(10.0),
            child: const Text(
              'Gradient Button',
              style: TextStyle(fontSize: 20)
            ),
          ),
        ),
      ],
    ),
  );
}

相對於column的垂直排列,row就是讓子組件能夠水平排列。
用法也很類似,一樣有個Expanded widget可以填滿水平空間。
同樣row也是不能捲動(scroll),若有捲動需求還是得參考ListView。
下方範例示範水平排列並且填滿可用空間。
Row(
  children: <Widget>[
    Expanded(
      child: Text('Deliver features faster', textAlign: TextAlign.center),
    ),
    Expanded(
      child: Text('Craft beautiful UIs', textAlign: TextAlign.center),
    ),
    Expanded(
      child: FittedBox(
        fit: BoxFit.contain, // otherwise the logo will be tiny
        child: const FlutterLogo(),
      ),
    ),
  ],
)

在前一天的文章裡有稍微提到這個widget,我的認知這是個比較跟佈局有關的widget。
這個class針對drawers、snack bars和bottom sheets提供了多種APIs。
在這個展示的範例,Scaffold內有body和FloatingActionButton兩個屬性。在Body內有一個Text Widget被包在Center內,然後FloatingActionButton連動一個callback去進行計數的動作。
int _count = 0;
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Sample Code'),
    ),
    body: Center(
      child: Text('You have pressed the button $_count times.')
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () => setState(() => _count++),
      tooltip: 'Increment Counter',
      child: const Icon(Icons.add),
    ),
  );
}

用來顯示單一樣式的文字,文字斷點的位置取決於佈局的限制。
下方範例針對超過限制的文字,改以...顯示:
Text(
  'Hello, $_name! How are you?',
  textAlign: TextAlign.center,
  overflow: TextOverflow.ellipsis,
  style: TextStyle(fontWeight: FontWeight.bold),
)
若要顯示一段文字,並且設定為不同樣式時,可以用Text.rich:
const Text.rich(
  TextSpan(
    text: 'Hello', // default text style
    children: <TextSpan>[
      TextSpan(text: ' beautiful ', style: TextStyle(fontStyle: FontStyle.italic)),
      TextSpan(text: 'world', style: TextStyle(fontWeight: FontWeight.bold)),
    ],
  ),
)
到這裡,應該可以體會Flutter是由很多個Widgets組成,光是basics widget就有這麼多,但熟悉了這些,要套用其他分類的widgets就快很多了。
明天會繼續介紹其他常見的UI Widgets,
https://flutter.dev/docs/development/ui/widgets/basics
第2點 children: <Widget>前面是不是要加上 const?
初學照做,vscode會出現藍波,解決方法加上const後就正常了,
再請大師指點,謝謝。
Column(
  children: const <Widget>[
    Text('Deliver features faster'),
    Text('Craft beautiful UIs'),
    Expanded(
      child: FittedBox(
        fit: BoxFit.contain, // otherwise the logo will be tiny
        child: const FlutterLogo(),
      ),
    ),
  ],
)